【第2191期】ECMAScript2021新特征
前言
今日前端早读课文章由凹凸实验室@五米授权分享。
正文从这开始~~
ECMAScript 2021版本预计在2021年6月发布,根据每年的新特性都会经历四个阶段,而第四阶段也就是最后一个阶段,本文即将介绍的即提案4中的相关新特性,意味着这些新特性将很大程度的出现在下一个版本中。
新特性总结如下:
String.prototype.replaceAll( )
私有方法 Private Methods 与私有访问者 Private Accessors
Promise.any 与 AggregateError
WeakRefs 弱引用
逻辑运算符和赋值表达式
String.prototype.replaceAll( )
完全匹配替换字符串
目前,JavaScript字符串有replace方法可以用来做一个字符串替换,
const str = "Backbencher sits at the Back"
const newStr = str.replace("Back", "Front")
console.log(newStr) // "Frontbencher sits at the Back"
如果是要完全匹配我们只能用正则表达式,如下
const str = "Backbencher sits at the Back"
const newStr = str.replace(/Back/g, "Front")
console.log(newStr) // "Frontbencher sits at the Front"
使用replaceAll
const str = "Backbencher sits at the Back"
const newStr = str.replaceAll("Back", "Front")
console.log(newStr) // "Frontbencher sits at the Front"
私有方法 Private Methods
私有方法
私有方法只能在定义它的类内部访问,专用方法名称以开头 #
class Person {
// Private method
#setType() {
console.log("I am Private");
}
// Public method
show() {
this.#setType();
}
}
const personObj = new Person()
personObj.show() // "I am Private"
personObj.setType() // TypeError: personObj.setType is not a function
由于setType()是私有方法,所以personObj.setType返回undefined,用undefined作函数会 引发TypeError。
私有访问者 Private Accessors
私有访问者
可以通过 #
在函数名称前添加访问器函数来使其私有
class Person {
// Public accessor
get name() { return "Backbencher" }
set name(value) {}
// Private accessor
get #age() { return 42 }
set #age(value) {}
}
在上面的代码get和set关键字中,创建name了一个accessor属性。使name看起来像一个函数,也可以像普通属性一样读取它, 而age则是私有。
const obj = new Person()
console.log(obj.name) // "Backbencher"
console.log(obj.age) // undefined
Promise.any 与 AggregateError
当Promise列表中的任意一个promise成功resolve则返回第一个resolve的结果状态, 如果所有的promise均reject,则抛出异常表示所有请求失败
Promise.any([
new Promise((resolve, reject) => setTimeout(reject, 200, 'Third')),
new Promise((resolve, reject) => setTimeout(resolve, 1000, 'Second')),
new Promise((resolve, reject) => setTimeout(resolve, 2000, 'First')),
])
.then(value => console.log(`Result: ${value}`)) // Result: Second
.catch (err => console.log(err))
另一种情况
Promise.any([
Promise.reject('Error 1'),
Promise.reject('Error 2'),
Promise.reject('Error 3')
])
.then(value => console.log(`请求结果: ${value}`))
.catch (err => console.log(err)) //AggregateError: All promises were rejected
Promise.any与Promise.race十分容易混淆,务必注意区分,Promise.race 一旦某个promise触发了resolve或者reject,就直接返回了该状态结果,并不在乎其成功或者失败。
WeakRefs
使用WeakRefs的Class类创建对对象的弱引用
当我们通过(const、let、var)创建一个变量时,垃圾收集器GC将永远不会从内存中删除该变量,只要它的引用仍然存在可访问。而WeakRef对象包含对对象的弱引用,对对象的弱引用是不会阻止垃圾收集器GC恢复该对象的引用,则GC可以在任何时候删除它,目前,可以通过WeakMap()或者WeakSet()来使用WeakRefs。
举个例子:想要跟踪特定的对象调用某一特定方法的次数,超过1000条则做对应提示
let map = new Map()
function doSomething(obj){
...
}
function useObject(obj){
doSomething(obj)
let called = map.get(obj) || 0
called ++
if(called>1000){
console.log('当前调用次数已经超过1000次了')
}
map.set(obj, called)
}
如上虽然可以实现我们的功能,但是会发生内存溢出,因为传递给doSomething函数的每个对象都永久保存在map中,并且不会被GC回收,因此我们可以使用WeakMap
let wmap = new WeakMap()
function doSomething(obj){
...
}
function useObject(obj){
doSomething(obj)
let called = wmap.get(obj) || 0
called ++
if(called>1000){
console.log('当前调用次数已经超过1000次了')
}
wmap.set(obj, called)
}
因为是弱引用,所以WeakMap、WeakSet的键值对是不可枚举的 WeakSet和WeakMap相似,但是每个对象在WeakSet中的每个对象只可能出现一次,WeakSet中所有对象都是唯一的
let ws = new WeakSet()
let foo = {}
let bar = {}
ws.add(foo)
ws.add(bar)
ws.has(foo) //true
ws.has(bar) //true
ws.delete(foo) //删除foo对象
ws.has(foo) //false 已删除
ws.has(bar) //仍存在
WeakSet与Set相比有以下两个区别
WeakSet只能是对象集合,而不能是任何类型的任意值
WeakSet弱引用,集合中对象引用为弱引用,如果没有其他对WeakSet对象的引用,则会被GC回收
最后,WeakRef实例有一个方法deref,返回引用的原始对象,如果原始对象被回收,则返回undefined
const cache = new Map()
const setValue = (key, obj) => {
cache.set(key, new WeakRef(obj))
}
const getValue = (key) => {
const ref = cache.get(key)
if (ref) {
return ref.deref()
}
}
const fibonacciCached = (number) => {
const cached = getValue(number)
if (cached) return cached
const sum = calculateFibonacci(number)
setValue(number, sum)
return sum
}
对于缓存远程数据来说,这可能不是一个好主意,因为远程数据可能会不可预测地从内存中删除。在这种情况下,最好使用LRU之类的缓存。
逻辑运算符和赋值表达式
a ||= b
//等价于
a = a || (a = b)
a &&= b
//等价于
a = a && (a = b)
a ??= b
//等价于
a = a ?? (a = b)
??= 可用来初始化缺失的属性
const pages = [
{
title:'主要场景',
path:'/'
},
{
path:'/a'
},
{
path:'/b'
},
]
for (const page of pages){
page.title ??= '默认标题'
}
console.table(pages)
//(index) title path
//0 "主要场景" "/"
//1 "默认标题" "/a"
//2 "默认标题" "/b"
小结:
a ||= b:当a值不存在时,将b变量赋值给a
a &&= b:当a值存在时,将b变量赋值给a
a ??= b:当a值为null或者undefined时,将b变量赋值给a
参考文章
https://backbencher.dev/javascript/es2021-new-features
https://codeburst.io/exciting-features-of-javascript-es2021-es12-1de8adf6550b
关于本文 作者:@五米 原文:https://jelly.jd.com/article/5febdfbb846cc00148ae36d7
为你推荐
【第1462期】赶上 ECMAScript 潮流:用现代 JavaScript 编程
欢迎自荐投稿,前端早读课等你来